home *** CD-ROM | disk | FTP | other *** search
- #ifdef TLI
-
- /*
- * from_tli() determines the type of transport (connected, unconnected), and
- * the name and address of the host at the other end of standard input. A
- * host name of "stdin" is returned if the program is run from a tty. All
- * results are in static or allocated memory. from_tli() assumes that its
- * result argument is already initialized with default values.
- *
- * The software attempts to determine the transport protocol that sits
- * underneath the TLI interface. In the case of TCP/IP, it immedately falls
- * back to familiar concepts and primitives: sockets, DNS, and so on, so
- * that we get the same functionality as with socket-based applications. In
- * all other cases the network addres results will be in some sort of
- * generic transport-independent form, and functionality will be limited (no
- * remote username lookups and no net/mask address patterns).
- *
- * The return status is (-1) if the remote host pretends to have someone elses
- * host name, otherwise a zero status is returned.
- *
- * Diagnostics are reported through syslog(3).
- *
- * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#) from_tli.c 1.1 93/07/02 16:33:49";
- #endif
-
- /* System libraries. */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mkdev.h>
- #include <sys/tiuser.h>
- #include <sys/timod.h>
- #include <stdio.h>
- #include <syslog.h>
- #include <errno.h>
- #include <netconfig.h>
- #include <netdir.h>
-
- extern int errno;
- extern char *sys_errlist[];
- extern int sys_nerr;
- extern int t_errno;
- extern char *t_errlist[];
- extern int t_nerr;
-
- /* Local stuff. */
-
- #include "log_tcp.h"
-
- /* Forward declarations. */
-
- static int tli_host();
- static int tli_match();
- static char *tli_error();
- static void tli_sink();
-
- /* The following are to be used in assignment context, not in comparisons. */
-
- #define GOOD 1
- #define BAD 0
-
- /* from_tli - determine name and address of remote endpoint */
-
- int from_tli(f)
- struct from_host *f;
- {
- void *handlep;
- struct netconfig *config;
- struct t_unitdata *unit;
- int flags;
- struct stat from_stdin;
- struct stat from_netconf;
-
- /*
- * Allocate storage for the endpoint address. t_alloc() finds out for us
- * how large the address can be. Address sizes depend on the underlying
- * transport protocol.
- */
-
- if ((unit = (struct t_unitdata *) t_alloc(0, T_UNITDATA, T_ADDR)) == 0) {
- syslog(LOG_ERR, "t_alloc: %s", tli_error());
- return (0);
- }
-
- /*
- * Get the transport-independent source address. In case of a datagram
- * service, peek at the sender address of the pending datagram without
- * popping the data off the receive queue. This trick works because the
- * data member of the unitdata structure has not been allocated.
- */
-
- if (ioctl(0, TI_GETPEERNAME, &(unit->addr)) >= 0) { /* assume connected */
- f->sock_type = FROM_CONNECTED;
- } else {
- switch (errno) {
- default:
- if (isatty(0)) {
- f->name = "stdin";
- return (0);
- } else {
- syslog(LOG_ERR, "TI_GETPEERNAME: %m");
- return (0);
- }
- case ENOTCONN: /* maybe unconnected */
- if (t_rcvudata(0, unit, &flags) < 0) {
- syslog(LOG_ERR, "t_rcvudata: %s", tli_error());
- return (0);
- }
- f->sock_type = FROM_UNCONNECTED;
- f->sink = tli_sink;
- break;
- }
- }
-
- /*
- * In order to map the raw transport address to a human-readable form we
- * must know what transport is involved. Assuming that the network device
- * is a clone device, we must compare the major device number of stdin to
- * the minor device number of the devices listed in the netconfig table.
- */
-
- if (fstat(0, &from_stdin) != 0) {
- syslog(LOG_ERR, "fstat(stdin): %m");
- return (0);
- }
- if ((handlep = setnetconfig()) == 0) {
- syslog(LOG_ERR, "setnetconfig: %m");
- return (0);
- }
- while (config = getnetconfig(handlep)) {
- if (stat(config->nc_device, &from_netconf) == 0) {
- if (minor(from_netconf.st_rdev) == major(from_stdin.st_rdev))
- break;
- }
- }
- if (config == 0) {
- syslog(LOG_ERR, "unable to identify transport protocol");
- return (0);
- }
-
- /*
- * Someone else may clobber the getnetconfig() result, so we'd better
- * acquire our private copy.
- */
-
- if ((config = getnetconfigent(config->nc_netid)) == 0) {
- syslog(LOG_ERR, "getnetconfigent(%s): %s",
- config->nc_netid, nc_sperror());
- return (0);
- }
-
- /*
- * Now that we know the underlying transport protocol, map the address to
- * a human-readble form, and determine the host name. Do DNS lookups if
- * it turns out that we are using an IP transport, after all. Otherwise,
- * use the transport-independent method and stick to generic network
- * addresses. XXX hard-coded protocol family name.
- */
-
- if (strcasecmp(config->nc_protofmly, "inet") == 0) {
- return (ip_host(f, (struct sockaddr_in *) (unit->addr.buf)));
- } else {
- return (tli_host(f, &(unit->addr), config));
- }
- }
-
- /* tli_host - map TLI transport address to human-readable address and name */
-
- static int tli_host(f, taddr, config)
- struct from_host *f;
- struct netbuf *taddr;
- struct netconfig *config;
- {
- struct nd_hostservlist *service;
-
- /*
- * Given the transport type we know how to map the transport address to
- * human-readable address, and how to map it to a host name. All results
- * are dynamically allocated so we do not need to make copies. XXX Some
- * transports may not have a universal textual address representation. In
- * those cases we will not be able to verify the host name.
- */
-
- if ((f->addr = taddr2uaddr(config, taddr)) == 0)
- f->addr = FROM_UNKNOWN;
-
- if (netdir_getbyaddr(config, &service, taddr) != ND_OK)
- return (0);
- f->name = service->h_hostservs->h_host;
-
- /*
- * Verify that the host name does not belong to someone else. If host
- * name verification fails, pretend that the host name lookup failed.
- */
-
- if (tli_match(config, service->h_hostservs, f->addr)) {
- return (0);
- } else {
- f->name = FROM_UNKNOWN;
- return (-1); /* verification failed */
- }
- }
-
- /* tli_match - determine if host name matches transport address */
-
- static int tli_match(config, service, uaddr)
- struct netconfig *config;
- struct nd_hostserv *service;
- char *uaddr;
- {
- struct nd_addrlist *addr_list;
- char *ua;
- int i;
-
- if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
-
- /*
- * Unable to verify that the name matches the address. This may
- * be a transient problem or a botched name server setup. We decide
- * to play safe.
- */
-
- syslog(LOG_ERR, "netdir_getbyname(%s): host address lookup failed",
- service->h_host);
- return (BAD);
-
- } else {
-
- /*
- * Look up the host address in the address list we just got. The
- * comparison is done on the textual representation, because the
- * transport address is an opaque structure that may have holes.
- */
-
- for (i = 0; i < addr_list->n_cnt; i++) {
- if (ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) {
- if (strcmp(ua, uaddr) == 0)
- return (GOOD);
- free(ua);
- }
- }
-
- /*
- * The host name does not map to the original host address. Perhaps
- * someone has compromised a name server. More likely someone botched
- * it, but that could be dangerous, too.
- */
-
- syslog(LOG_ERR, "host name/address mismatch: %s != %s",
- uaddr, service->h_host);
- return (BAD);
- }
- }
-
- /* tli_error - convert tli error number to text */
-
- static char *tli_error()
- {
- static char buf[40];
-
- if (t_errno != TSYSERR) {
- if (t_errno < 0 || t_errno >= t_nerr) {
- sprintf(buf, "Unknown TLI error %d", t_errno);
- return (buf);
- } else {
- return (t_errlist[t_errno]);
- }
- } else {
- if (errno < 0 || errno >= sys_nerr) {
- sprintf(buf, "Unknown UNIX error %d", errno);
- return (buf);
- } else {
- return (sys_errlist[errno]);
- }
- }
- }
-
- /* tli_sink - absorb unreceived datagram */
-
- static void tli_sink()
- {
- struct t_unitdata *unit;
- int flags;
-
- /*
- * Something went wrong. Absorb the datagram to keep inetd from looping.
- * Allocate storage for address, control and data. If that fails, sleep
- * for a couple of seconds in an attempt to keep inetd from looping too
- * fast.
- */
-
- if ((unit = (struct t_unitdata *) t_alloc(0, T_UNITDATA, T_ALL)) == 0) {
- syslog(LOG_ERR, "t_alloc: %s", tli_error());
- sleep(5);
- } else {
- (void) t_rcvudata(0, unit, &flags);
- }
- }
-
- #endif /* TLI */
-